package com.ltsh.fim.client;

import com.alibaba.fastjson.JSONObject;
import com.ltsh.fim.client.handler.FimClientHandler;
import com.ltsh.fim.client.model.LoginReq;
import com.ltsh.fim.common.enums.RequestType;
import com.ltsh.fim.common.impl.MyEncoderImpl;
import com.ltsh.fim.common.inf.MyEncoder;
import com.ltsh.fim.common.inf.ResultCallback;
import com.ltsh.fim.common.model.FimFuture;
import com.ltsh.fim.common.model.FimRequest;
import com.ltsh.fim.common.model.FimRequestHolder;
import com.ltsh.fim.common.model.req.BaseLoginReq;
import com.ltsh.fim.common.model.req.BaseReq;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.DatagramPacket;
import io.netty.channel.socket.nio.NioDatagramChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sun.misc.Request;

import java.net.InetSocketAddress;

public class DefaultFimClientContext implements FimClientContext {
    private static Logger logger = LoggerFactory.getLogger(DefaultFimClientContext.class);

    private EventLoopGroup eventLoopGroup;
    private Bootstrap bootstrap;
    private Channel channel;
    private int localPort = 7070;
    private String serviceHost;
    private int servicePort;

    private UserToken userToken = new UserToken();
    private MyEncoder myEncoder = new MyEncoderImpl();

    public DefaultFimClientContext(int localPort, String serviceHost, int servicePort){
        this.localPort = localPort;
        this.serviceHost = serviceHost;
        this.servicePort = servicePort;
        eventLoopGroup = new NioEventLoopGroup();
        bootstrap = new Bootstrap();
        bootstrap.group(eventLoopGroup).channel(NioDatagramChannel.class)
                .option(ChannelOption.SO_BROADCAST, true)
                .handler(new FimClientHandler());
        try {
            channel = bootstrap.bind(this.localPort).sync().channel();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    /**
     * 发送消息
     * @param baseReq
     */
    public void sendMsg(BaseReq baseReq, byte type, ResultCallback resultCallback) {
        if(baseReq instanceof BaseLoginReq) {
            ((BaseLoginReq)baseReq).setUserToken(userToken.getToken());
        }
        FimRequest fimRequest = new FimRequest();
        fimRequest.setType(type);
        fimRequest.setData(JSONObject.toJSONBytes(baseReq));
        if(resultCallback != null) {
            FimFuture rpcFuture = new FimFuture();
            rpcFuture.setResultCallback(resultCallback);
            FimRequestHolder.put(String.valueOf(fimRequest.getId()), rpcFuture);
        }
        try {
//            buffer.writeBytes(Constant.SEPARATOR);
            System.out.println("发送消息:" + JSONObject.toJSONString(baseReq));
//            request.setUserToken(userToken.getToken());
            ByteBuf byteBuf = myEncoder.encoding(fimRequest);
            channel.writeAndFlush(
                    new DatagramPacket(
                        byteBuf,
                        new InetSocketAddress(serviceHost, servicePort)
                    )
            ).sync();
            if (!channel.closeFuture().await(15000)) {
                System.out.println("out of time");
            }
//            writeAndFlush(buffer);

        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
    }

    /**
     * 登录
     * @param userName
     * @param password
     * @param status
     */
    public void login(String userName, String password, int status, ResultCallback resultCallback) {
        LoginReq loginReq = new LoginReq();
        loginReq.setLoginName(userName);
        loginReq.setPassword(password);
        loginReq.setUserType(status);

        sendMsg(loginReq, RequestType.LOGIN_REQ.getValue(), new ResultCallback() {
            @Override
            public void callback(Object result) {
                FimRequest fimRequest1 = (FimRequest) result;
                DefaultFimClientContext.this.userToken = JSONObject.parseObject(fimRequest1.getContext(), UserToken.class);
                resultCallback.callback(result);
            }
        });
    }

    /**
     * 登录退出
     */
    public void loginOut(ResultCallback resultCallback) {
        this.userToken = new UserToken();
        sendMsg(new BaseLoginReq(), RequestType.LOGIN_OUT_REQ.getValue(), resultCallback);
    }

}
